﻿using System;
using System.Threading;

namespace Rsdn.SmartApp
{
	/// <summary>
	/// Реализация паттерна IDisposable для <see cref="ReaderWriterLockSlim"/>
	/// </summary>
	public static class ReaderWriterLockHelper
	{
		/// <summary>
		/// Получить лок для читающего.
		/// </summary>
		public static IDisposable GetReaderLock(this ReaderWriterLockSlim readerWriterLock)
		{
			return new ReaderLock(readerWriterLock);
		}

		/// <summary>
		/// Получить лок для пишущего.
		/// </summary>
		public static IDisposable GetWriterLock(this ReaderWriterLockSlim readerWriterLock)
		{
			return new WriterLock(readerWriterLock);
		}

		/// <summary>
		/// Получить лок для читающего с возможностью апгрейда до пишущего.
		/// </summary>
		public static IDisposable GetUpgradableReaderLock(this ReaderWriterLockSlim readerWriterLock)
		{
			return new UpgradableReaderLock(readerWriterLock);
		}

		#region ReaderLock class
		private class ReaderLock : IDisposable
		{
			private readonly ReaderWriterLockSlim m_ReaderWriterLock;

			public ReaderLock(ReaderWriterLockSlim readerWriterLock)
			{
				m_ReaderWriterLock = readerWriterLock;
				m_ReaderWriterLock.EnterReadLock();
			}

			#region IDisposable Members
			public void Dispose()
			{
				m_ReaderWriterLock.ExitReadLock();
			}
			#endregion
		}
		#endregion

		#region WriterLock class
		private class WriterLock : IDisposable
		{
			private readonly ReaderWriterLockSlim m_ReaderWriterLock;

			public WriterLock(ReaderWriterLockSlim readerWriterLock)
			{
				m_ReaderWriterLock = readerWriterLock;
				m_ReaderWriterLock.EnterWriteLock();
			}

			#region IDisposable Members
			public void Dispose()
			{
				m_ReaderWriterLock.ExitWriteLock();
			}
			#endregion
		}
		#endregion

		#region UpgradableReaderLock class
		private class UpgradableReaderLock : IDisposable
		{
			private readonly ReaderWriterLockSlim m_ReaderWriterLock;

			public UpgradableReaderLock(ReaderWriterLockSlim readerWriterLock)
			{
				m_ReaderWriterLock = readerWriterLock;
				m_ReaderWriterLock.EnterUpgradeableReadLock();
			}

			#region IDisposable Members
			public void Dispose()
			{
				m_ReaderWriterLock.ExitUpgradeableReadLock();
			}
			#endregion
		}
		#endregion
	}
}
